package com.ly.bluetoothlowenergydemo;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.util.Formatter;
import java.util.UUID;

/**
 * 蓝牙工具类
 * 功能：
 * 1、搜索蓝牙设备
 * 2、连接蓝牙串口
 * 3、发送串口数据
 * 4、接收串口数据
 *
 * @author Liuyang
 * @date 2020/5/28
 */
public class BLESPPUtils {
    private static boolean enableLogout = false;
    private Context context;
    private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    private OnBluetoothAction onBluetoothAction;
    private ConnectTask connectTask = new ConnectTask();

    /**
     * 搜索到新设备的广播接收器
     */
    private final BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (onBluetoothAction != null) {
                    onBluetoothAction.onFoundDevice(device);
                }
            }
        }
    };

    /**
     * 搜索结束的广播接收器
     */
    private final BroadcastReceiver finishFoundReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                if (onBluetoothAction != null) {
                    onBluetoothAction.onFinishFoundDevice();
                }
            }
        }
    };

    /**
     * 连接任务
     */
    private static class ConnectTask extends AsyncTask<String, Byte[], Void> {
        private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        BluetoothSocket bluetoothSocket;
        BluetoothDevice remoteDevice;
        OnBluetoothAction onBluetoothAction;
        boolean isRunning = false;
        String stopString = "\r\n";

        @Override
        protected Void doInBackground(String... bluetoothDevicesMac) {
            // 记录标记位，开始运行
            isRunning = true;

            // 尝试获取 bluetoothStock
            try {
                UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
                remoteDevice = bluetoothAdapter.getRemoteDevice(bluetoothDevicesMac[0]);
                bluetoothSocket = remoteDevice.createRfcommSocketToServiceRecord(SPP_UUID);
            } catch (Exception e) {
                logD("获取Stock失败");
                isRunning = false;
                e.printStackTrace();
                return null;
            }

            // 检查有没有获取到
            if (bluetoothSocket == null) {
                onBluetoothAction.onConnectFailed("连接失败：获取Stock失败!");
                isRunning = false;
                return null;
            }

            // 尝试连接
            try {
                // 等待连接，会阻塞线程
                bluetoothSocket.connect();
                logD("连接成功");
                onBluetoothAction.onConnectSuccess(remoteDevice);
            } catch (Exception connectException) {
                connectException.printStackTrace();
                logD("连接失败" + connectException.getMessage());
                onBluetoothAction.onConnectFailed("连接失败：" + connectException.getMessage());
                return null;
            }

            // 开始监听数据接收
            try {
                InputStream inputStream = bluetoothSocket.getInputStream();
                byte[] result = new byte[0];
                while (isRunning) {
                    logD("looping");
                    byte[] buffer = new byte[256];
                    // 等待有数据
                    while (inputStream.available() == 0 && isRunning) {
                        if (System.currentTimeMillis() < 0) {
                            break;
                        }
                    }
                    while (isRunning) {
                        try {
                            int num = inputStream.read(buffer);
                            byte[] temp = new byte[result.length + num];
                            System.arraycopy(result, 0, temp, 0, result.length);
                            System.arraycopy(buffer, 0, temp, result.length, num);
                            result = temp;
                            if (inputStream.available() == 0) {
                                break;
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            onBluetoothAction.onConnectFailed("接收数据单次失败：" + e.getMessage());
                            break;
                        }
                    }

                    try {
                        // 返回数据
                        logD("当前累计收到的数据量 => " + byte2Hex(result));
                        byte[] stopFlag = stopString.getBytes();
                        int stopFlagSize = stopFlag.length;
                        boolean shouldCallOnReceiveBytes = false;
                        logD("标志位为：" + byte2Hex(stopFlag));
                        for (int i = stopFlagSize - 1; i >= 0; i--) {
                            int indexResult = result.length - (stopFlagSize - i);
                            if (indexResult >= result.length || indexResult < 0) {
                                shouldCallOnReceiveBytes = false;
                                logD("收到的数据比停止字符串短");
                                break;
                            }
                            if (stopFlag[i] == result[indexResult]) {
                                logD("发现" + byte2Hex(stopFlag[i]) + "等于" + byte2Hex(result[indexResult]));
                                shouldCallOnReceiveBytes = true;
                            } else {
                                logD("发现" + byte2Hex(stopFlag[i]) + "不等于" + byte2Hex(result[indexResult]));
                                shouldCallOnReceiveBytes = false;
                            }
                        }

                        if (shouldCallOnReceiveBytes) {
                            onBluetoothAction.onReceiveBytes(result);
                            // 清空
                            result = new byte[0];
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        onBluetoothAction.onConnectFailed("验证收到数据结束标志出错：" + e.getMessage());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                onBluetoothAction.onConnectFailed("连接失败：" + e.getMessage());
            }

            return null;
        }

        @Override
        protected void onCancelled() {
            try {
                logD("AsyncTask开始释放资源");
                isRunning = false;
                bluetoothSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        /**
         * 发送
         *
         * @param msg 内容
         */
        void send(byte[] msg) {
            try {
                bluetoothSocket.getOutputStream().write(msg);
                onBluetoothAction.onSendBytes(msg);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 设置停止标志位字符串
     *
     * @param stopString 停止位字符串
     */
    @SuppressWarnings("SameParameterValue")
    void setStopString(String stopString) {
        connectTask.stopString = stopString;
    }

    /**
     * 构造函数
     */
    BLESPPUtils(Context context, OnBluetoothAction onBluetoothAction) {
        this.context = context;
        this.onBluetoothAction = onBluetoothAction;
    }

    /**
     * 初始化
     */
    void onCreate() {
        IntentFilter fountFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        context.registerReceiver(receiver, fountFilter);
        IntentFilter finishFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        context.registerReceiver(finishFoundReceiver, finishFilter);
    }

    /**
     * 释放资源
     */
    void onDestory() {
        try {
            logD("onDestory：开始释放资源.");
            connectTask.isRunning = false;
            connectTask.cancel(true);
            context.unregisterReceiver(receiver);
            context.unregisterReceiver(finishFoundReceiver);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 开始搜索
     */
    void startDiscovery() {
        if (bluetoothAdapter.isDiscovering()) {
            bluetoothAdapter.cancelDiscovery();
        }
        bluetoothAdapter.startDiscovery();
    }

    /**
     * 连接搜索到的设备，获取数据
     *
     * @param device 设备
     */
    void connect(BluetoothDevice device) {
        bluetoothAdapter.cancelDiscovery();
        connect(device.getAddress());
    }

    /**
     * 使用Mac地址连接
     *
     * @param deviceMac Mac地址
     */
    private void connect(String deviceMac) {
        if (connectTask.getStatus() == AsyncTask.Status.RUNNING && connectTask.isRunning) {
            if (onBluetoothAction != null) {
                onBluetoothAction.onConnectFailed("有正在连接的任务");
            }
            return;
        }
        connectTask.onBluetoothAction = onBluetoothAction;
        try {
            connectTask.execute(deviceMac);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送 byte 数组到串口
     *
     * @param bytes 要发送的数据
     */
    void send(byte[] bytes) {
        if (connectTask != null) {
            connectTask.send(bytes);
        }
    }

    /**
     * 获取用户是否打开了蓝牙
     */
    boolean isBluetoothEnable() {
        return bluetoothAdapter.isEnabled();
    }

    /**
     * 开启蓝牙
     */
    void enableBluetooth() {
        bluetoothAdapter.enable();
    }


    /**
     * 字节转换成16进制字符串
     *
     * @param b 字节
     * @return 字符串
     */
    private static String byte2Hex(byte b) {
        StringBuilder hex = new StringBuilder(Integer.toHexString(b));
        if (hex.length() > 2) {
            hex = new StringBuilder(hex.substring(hex.length() - 2));
        }
        while (hex.length() < 2) {
            hex.insert(0, "0");
        }
        return hex.toString();
    }

    /**
     * 字节数组转换成16进制字符串
     *
     * @param bytes 字节数组
     * @return 字符串
     */
    private static String byte2Hex(byte[] bytes) {
        Formatter formatter = new Formatter();
        for (byte b : bytes) {
            formatter.format("%02x", b);
        }
        String hash = formatter.toString();
        formatter.close();
        return hash;
    }

    /**
     * 启用日志输出
     */

    void setEnableLogOut() {
        enableLogout = true;
    }

    /**
     * 打印日志
     */
    private static void logD(String msg) {
        if (enableLogout) {
            Log.d("allen", msg);
        }
    }

    /**
     * 蓝牙活动回调
     */
    public interface OnBluetoothAction {
        /**
         * 发现新设备
         *
         * @param device 设备
         */
        void onFoundDevice(BluetoothDevice device);

        /**
         * 连接成功
         *
         * @param device 设备
         */
        void onConnectSuccess(BluetoothDevice device);

        /**
         * 连接失败
         *
         * @param msg 信息
         */
        void onConnectFailed(String msg);

        /**
         * 接收到 bytes 数组
         *
         * @param bytes 内容
         */
        void onReceiveBytes(byte[] bytes);

        /**
         * 发送 bytes 数组
         *
         * @param bytes 内容
         */
        void onSendBytes(byte[] bytes);

        /**
         * 结束搜索设备
         */
        void onFinishFoundDevice();
    }
}

